import cv2
import math
import unittest

class Point():
    def __init__(self,X=0,Y=0):
        self.X = X
        self.Y = Y

class Line():
    def __init__(self,point1,point2):
        self.point1 = point1
        self.point2 = point2

#返回校准的正脸关键点
def get_frontFace_template(face_detector,landmark_detector):
    '''
    :param face_detector:
    :param landmark_detector:
    :return: 获取校准正脸中的landmark
    '''
    calibrate_faceImg = cv2.imread("service/front_face.png")
    calibrate_faceImg = cv2.resize(calibrate_faceImg,(640,480),interpolation=cv2.INTER_CUBIC)
    dets = face_detector.detect_faces(calibrate_faceImg)[0]
    cal_landmark = landmark_detector.detect_landmarks(calibrate_faceImg, [dets])
    #人脸关键点居中表示
    cal_landmark = landmark_centerize(cal_landmark,calibrate_faceImg)
    # landmarkPlot(calibrate_faceImg,cal_landmark[0])
    # cv2.imshow("res",calibrate_faceImg)
    return cal_landmark

def landmark_centerize(landmark,img):
    '''
    :param landmark: cal_landmark.shape = [1,n,68,2]
    :param img:
    :return:
    '''
    height,width,_ = img.shape
    center_x = width / 2
    center_y = height/2
    #鼻子关键点 29
    nose_x,nose_y = landmark[0][0][29][0],landmark[0][0][29][1]
    diff_x,diff_y = nose_x - center_x, nose_y - center_y
    for i in range(0,len(landmark[0][0])):
        landmark[0][0][i][0] -= diff_x
        landmark[0][0][i][1] -= diff_y
    return landmark

#三庭五眼比较
def frontFace_judgement(cal_landmark, landmark, angle_error=15):
    '''
    :param cal_landmark: 校准的人脸关键点 shape = [68,2]
    :param landmark: 当前人脸关键点  shape = [68,2]
    :param angle_error: 两水平线段的最小夹角误差（0~180）
    :return:
    '''
    # 参考 https://blog.csdn.net/m0_37316917/article/details/102728869
    # 左眼水平参考线  36-39
    point1 = Point(cal_landmark[36][0],cal_landmark[36][1])
    point2 = Point(cal_landmark[39][0],cal_landmark[39][1])
    point3 = Point(landmark[36][0], landmark[36][1])
    point4 = Point(landmark[39][0], landmark[39][1])
    line1 = Line(point1,point2)
    line2 = Line(point3,point4)
    # angle1 = getAngle(line1,line2)
    intersection1 = is_intersection(point1,point2,point3,point4)

    # 右眼水平参考线  42-45
    point1 = Point(cal_landmark[42][0], cal_landmark[42][1])
    point2 = Point(cal_landmark[45][0], cal_landmark[45][1])
    point3 = Point(landmark[42][0], landmark[42][1])
    point4 = Point(landmark[45][0], landmark[45][1])
    line1 = Line(point1, point2)
    line2 = Line(point3, point4)
    # angle2 = getAngle(line1, line2)
    intersection2 = is_intersection(point1, point2, point3, point4)

    # 鼻梁垂直参考线  27-33
    point1 = Point(cal_landmark[27][0], cal_landmark[27][1])
    point2 = Point(cal_landmark[33][0], cal_landmark[33][1])
    point3 = Point(landmark[27][0], landmark[27][1])
    point4 = Point(landmark[33][0], landmark[33][1])
    line1 = Line(point1, point2)
    line2 = Line(point3, point4)
    # angle3 = getAngle(line1, line2)
    intersection3 = is_intersection(point1, point2, point3, point4)

    # 嘴巴水平参考线  48-54
    point1 = Point(cal_landmark[48][0], cal_landmark[48][1])
    point2 = Point(cal_landmark[54][0], cal_landmark[54][1])
    point3 = Point(landmark[48][0], landmark[48][1])
    point4 = Point(landmark[54][0], landmark[54][1])
    line1 = Line(point1, point2)
    line2 = Line(point3, point4)
    angle4 = getAngle(line1, line2)
    intersection4 = is_intersection(point1, point2, point3, point4)

    # flag1 = angle1 <= angle_error and angle2 <= angle_error and angle3 <= angle_error and angle4 <= angle_error
    flag2 = (intersection1 and intersection2) or (intersection1 and intersection3)\
            or (intersection1 and intersection4) or (intersection2 and intersection3)  \
            or (intersection2 and intersection4) or (intersection3 and intersection4)    #有两个相交就判定为正脸
    if(flag2):
        print("当前为正脸")
        return True
    else:
        return False

#获取两线段的夹角（0~180）
def getAngle(line1, line2):
    """
    计算两条线段之间的夹角
    :param line1:
    :param line2:
    :return:
    """
    # 参考 https: // blog.csdn.net / m0_37316917 / article / details / 102728869
    dx1 = line1.point1.X - line1.point2.X
    dy1 = line1.point1.Y - line1.point2.Y
    dx2 = line2.point1.X - line2.point2.X
    dy2 = line2.point1.Y - line2.point2.Y
    angle1 = math.atan2(dy1, dx1)
    angle1 = int(angle1 * 180 / math.pi)
    # print(angle1)
    angle2 = math.atan2(dy2, dx2)
    angle2 = int(angle2 * 180 / math.pi)
    # print(angle2)
    if angle1 * angle2 >= 0:
        insideAngle = abs(angle1 - angle2)
    else:
        insideAngle = abs(angle1) + abs(angle2)
        if insideAngle > 180:
            insideAngle = 360 - insideAngle
    insideAngle = insideAngle % 180
    return insideAngle

#判断两线段是否相交
def is_intersection_func(point1,point2,point3):
    # 参考https://blog.csdn.net/weixin_30950237/article/details/97030557
    m1 = (point1.X - point2.X) * (point1.Y - point3.Y)
    m2 = (point1.Y - point2.Y) * (point1.X - point3.X)
    return m1 - m2

def is_intersection(point1,point2,point3,point4):
    # 参考https://blog.csdn.net/weixin_30950237/article/details/97030557
    t1 = is_intersection_func(point1,point2,point3)
    t2 = is_intersection_func(point1,point2,point4)
    t3 = is_intersection_func(point3,point4,point1)
    t4 = is_intersection_func(point3,point4,point2)
    flag = False
    if(t1 * t2 <= 0 and t3 * t4 <= 0): flag = True
    return flag

#获取最大人脸
def getlargest_face(dets):
    if len(dets) == 1:
        return 0

    face_areas = [abs(det[0] - det[2]) * abs(det[1] - det[3]) for det in dets]

    largest_area = face_areas[0]
    largest_index = 0
    for index in range(1, len(dets)):
        if face_areas[index] > largest_area:
            largest_index = index
            largest_area = face_areas[index]

    print("largest_face index is {} in {} faces".format(largest_index, len(dets)))
    return largest_index

#人脸边界框绘制
def face_plot(frame,dets):
    '''
    :param dets: scrfd的人脸检测边界框
    :return:
    '''
    for det in dets:
        x1, y1, x2, y2, _ = det
        x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
        # 绘制人脸边框
        cv2.rectangle(frame, (x1, y1), (x2, y2), color=(0, 0, 255), thickness=2)  # 目标的bbox

#绘制人脸关键点
def landmarkPlot(frame, landmark,color=(0,255,0)):
    # 检测到人脸，绘制关键点
    if (len(landmark) != 0):
        # 绘制68个关键点
        for j in range(len(landmark)):
            for i in range(68):
                cv2.circle(frame, (tuple([int(landmark[j][i][0]), int(landmark[j][i][1])])), 2, color, -1, 8)
    return frame

class MyTest(unittest.TestCase):
    def test_intersection(self):
        point1 = Point(4,4)
        point2 = Point(2,2)
        point3 = Point(4,4)
        point4 = Point(0,8)
        flag = is_intersection(point1,point2,point3,point4)
        print(flag)